/*
 * md5model.h -- md5mesh model loader + animation
 *
 * Copyright (c) 2005-2007 David HENRY
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#ifndef __MD5MODEL_H__
#define __MD5MODEL_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "../../math/src/mgpi_math.h"

    /* Vectors */
    typedef float vvec2_t[2];
    typedef float vvec3_t[3];

    /* Quaternion (x, y, z, w) */
    typedef float quat4_t[4];

    /* Joint */
    struct _md5_joint {
        char name[64];
        int parent;

        float3 pos;
        float4 orient;
    };

    /* Vertex */
    struct _md5_vertex {
        float2 st;
		float3 normal;
		float3 binormal;
		float3 tangent;
		float4 pos;

        int start; /* start weight */
        int count; /* weight count */
    };

    /* Triangle */
    struct _md5_triangle {
        int index[3];
    };

    /* Weight */
    struct _md5_weight {
        int joint;
        float bias;

        vvec3_t pos;
    };

    /* Bounding box */
    struct _md5_bbox {
        float3 min;
        float3 max;
    };

    /* MD5 mesh */
    struct _md5_mesh {
        struct _md5_vertex *vertices;
        struct _md5_triangle *triangles;
        struct _md5_weight *weights;

        int num_verts;
        int num_tris;
        int num_weights;

        char shader[256];
    };

    /* MD5 model structure */
    struct _md5_model {
        GLuint texture;

        struct _md5_joint *baseSkel;
        struct _md5_mesh *meshes;

        int num_joints;
        int num_meshes;

        struct _md5_joint *skeleton_array;
        float3 *vertex_array;
        GLuint *index_array;
		float4 *texcoord_array;
		float3 *normal_array;
		float3 *tangent_array;
		float3 *binormal_array;
    };

    typedef struct _md5_model md5_model_t;

	
    /* Animation info */
    struct _anim_info {
        int curr_frame;
        int next_frame;

		double curr_time;
        double last_time;
        double max_time;
    };

    typedef struct _anim_info anim_info_t;

    /* Animation data */
    struct _md5_anim {
        int num_frames;
        int num_joints;
        int frameRate;

        struct _md5_joint **skelFrames;
        struct _md5_bbox *bboxes;
		struct _anim_info info;
    };

    typedef struct _md5_anim md5_anim_t;

    /* Joint info */
    struct _joint_info {
        char name[64];
        int parent;
        int flags;
        int startIndex;
    };

    /* Base frame joint */
    struct _baseframe_joint {
        float3 pos;
        quat4_t orient;
    };

    /**
     * Quaternion prototypes
     */
    void Quat_computeW(quat4_t q);
    void Quat_normalize(quat4_t q);
    void Quat_multQuat(const quat4_t qa, const quat4_t qb, quat4_t out);
    void Quat_multVec(const quat4_t q, const float3 v, quat4_t out);
    void Quat_rotatePoint(const quat4_t q, const float3 in, float3 out);
    float Quat_dotProduct(const quat4_t qa, const quat4_t qb);
    void Quat_slerp(const quat4_t qa, const quat4_t qb, float t, quat4_t out);

    /**
     * md5mesh prototypes
     */
    int gsubReadMD5Model(const char *filename, struct _md5_model *mdl, struct _md5_anim *anim);
    void gsubFreeMD5Model(struct _md5_model *mdl);
    void gsubPrepareMesh(const struct _md5_mesh *mesh, const struct _md5_joint *skeleton, struct _md5_model *mdl);
    void gsubFreeArrays(void);
    void gsubRenderMD5Model(struct _md5_model *mdl, struct _md5_anim *anim, int start, int stop, int num_passes);

    /**
     * md5anim prototypes
     */
    int gsubCheckAnimValidity(const struct _md5_model *mdl, const struct _md5_anim *anim);
    int gsubReadMD5Anim(const char *filename, struct _md5_anim *anim, struct _md5_model *mdl);
    void gsubFreeMD5Anim(struct _md5_anim *anim);
    void gsubInterpolateSkeletons(const struct _md5_joint *skelA, const struct _md5_joint *skelB, int num_joints, float interp, struct _md5_joint *out);
    void gsubAnimateMD5(const struct _md5_anim *anim, struct _anim_info *animInfo, double dt, int start, int stop);

#ifdef __cplusplus
}
#endif

#endif /* __MD5MODEL_H__ */
